﻿#include"snake.h"

//游戏的初始化
void Set_Game(Snake* ppsnake)
{
	//0.设置窗口的大小并隐藏光标
	Std_set();
	//1.欢迎界面
	Print_wel();
	//2.规则说明界面
	Print_rule();
	//3.绘制地图
	Print_wall();
	//4.绘制蛇
	Print_snake(ppsnake);
	//5.绘制食物
	Print_food(ppsnake);
}

//光标位置的设置
void Set_Con(int x, int y)
{
	HANDLE output = NULL;
	output = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coor = { x, y };
	SetConsoleCursorPosition(output, coor);
}


//0.设置窗口的大小并隐藏光标
void Std_set()
{
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO con;
	GetConsoleCursorInfo(houtput, &con);
	con.bVisible = false;
	SetConsoleCursorInfo(houtput, &con);
}

//1.欢迎界面
void Print_wel()
{
	Set_Con(40, 12);
	printf("欢迎来到贪吃蛇小游戏！！！\n\n\n\n");
	system("pause");
	system("cls");
}

//2.规则说明界面
void Print_rule()
{
	Set_Con(15, 10);
	printf("请用↑. ↓. ←. →控制蛇移动的方向，F3为加速，F4为减速，加速会获得更高的分数。\n\n\n\n\n\n\n");
	system("pause");
	system("cls");
}

//3.绘制地图
void Print_wall()
{
	for (int i = 0; i < 29; i++)
	{
		wprintf(L"%lc", L'□');
	}
	Set_Con(0, 26);
	for (int i = 0; i < 29; i++)
	{
		wprintf(L"%lc", L'□');
	}
	for (int i = 1; i < 26; i++)
	{
		Set_Con(0, i);
		wprintf(L"%lc", L'□');
	}
	for (int i = 1; i < 26; i++)
	{
		Set_Con(56, i);
		wprintf(L"%lc", L'□');
	}
}

//4.绘制蛇
void Print_snake(Snake* ppsnake) 
{
	snakeNode* cur = NULL;
	for (int i = 0; i < 5; i++)
	{
		cur = (snakeNode*)malloc(sizeof(snakeNode));
		if (cur == NULL)
		{
			perror("malloc");
			exit(1);
		}
		cur->x = 24 + 2 * i;
		cur->y = 5;
		cur->next = NULL;
		//尾插
		if (ppsnake->psnake == NULL)
		{
			ppsnake->psnake = cur;
		}
		else
		{
			cur->next = ppsnake->psnake;
			ppsnake->psnake = cur;
		}
	}
	cur = ppsnake->psnake;
	//打印蛇身
	while (cur)
	{
		Set_Con(cur->x, cur->y);
		wprintf(L"%lc", L'●');
	    cur = cur->next;
	}
	//设置食物分数
	ppsnake->foof_weight = 10;
	//总分
	ppsnake->score = 0;
	//速度
	ppsnake->sleep_time = 200;
	//初始方向
	ppsnake->dir = RIGHT;
	//游戏状态
	ppsnake->status = REGULAR;

}

//5.绘制食物
void Print_food(Snake* ppsnake)
{
	int x = 0;
	int y = 0;
again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	snakeNode* cur = ppsnake->psnake;
	while (cur)
	{
		if (cur->x == x && cur->y == y)
		{
			goto again;
		}
		cur = cur->next;
	}
	snakeNode*  p = (snakeNode*)malloc(sizeof(snakeNode));
	if (p == NULL)
	{
		perror("malloc");
		return;
	}
	p->x = x;
	p->y = y;
	p->next = NULL;
	Set_Con(x, y);
	wprintf(L"%lc", L'◆');
	ppsnake->pfood = p;
}

//打印帮助信息
void Print_help()
{
	Set_Con(64, 14);
	printf("按ESC退出游戏");
	Set_Con(64, 15);
	printf("按F3加速，按F4减速");
}

//暂停游戏
void PAUSE()
{
	while (1)
	{
		Sleep(100);
		if (KEY_PASS(VK_SPACE))
		{
			break;
		}
	}
}

//判断下一个结点是不是食物
int IF_FOOF(snakeNode* pnew, Snake* pp)
{
	return (pp->pfood->x == pnew->x && pp->pfood->y == pnew->y);
}

//是食物：
void EatFood(snakeNode* pnew, Snake* pp)
{
	//把新的结点加到蛇身上
	pp->pfood->next = pp->psnake;
	pp->psnake = pp->pfood;
	snakeNode* cur = pp->psnake;
	//释放新的结点
	free(pnew);
	pnew = NULL;
	//重新打印蛇身
	while (cur != NULL)
	{
		Set_Con(cur->x, cur->y);
		wprintf(L"%lc", L'●');
		cur = cur->next;
	}
	pp->score += pp->foof_weight;
	//创建新的食物：
	Print_food(pp);
}

//不是食物：
void NoFood(snakeNode* pnew, Snake* pp)
{
	//把新的结点加到蛇身上
	pnew->next = pp->psnake;
	pp->psnake = pnew;
	snakeNode* cur = pp->psnake;
	//重新打印蛇身
	while (cur->next->next != NULL)
	{
		Set_Con(cur->x, cur->y);
		wprintf(L"%lc", L'●');
		cur = cur->next;
	}
	Set_Con(cur->next->x, cur->next->y);
	printf("  ");
	//释放尾部结点
	free(cur->next);
	cur->next = NULL;
}

//撞到墙
void KillByWall(Snake* pp)
{
	if (pp->psnake->x == 0 || pp->psnake->x == 56 || pp->psnake->y == 0 || pp->psnake->y == 26)
	{
		pp->status = OVER_BY_WALL;
	}
}

//撞到自己
void KillBySelf(Snake* pp)
{
	snakeNode* cur = pp->psnake->next;
	while (cur)
	{
		if (cur->x == pp->psnake->x && cur->y == pp->psnake->y)
		{
			pp->status = OVER_BY_SELF;
			break;
		}
		cur = cur->next;
	}
}


//蛇的移动
void Snakemove(Snake* pp)
{
	snakeNode* pnew = (snakeNode*)malloc(sizeof(snakeNode));
	if (pnew == NULL)
	{
		perror("malloc");
		return;
	}
	switch (pp->dir)
	{
	case UP:
		pnew->x = pp->psnake->x;
		pnew->y = pp->psnake->y - 1;
		break;
	case DOWN:
		pnew->x = pp->psnake->x;
		pnew->y = pp->psnake->y + 1;
		break;
	case LEFT:
		pnew->x = pp->psnake->x - 2;
		pnew->y = pp->psnake->y;
		break;
	case RIGHT:
		pnew->x = pp->psnake->x + 2;
		pnew->y = pp->psnake->y;
		break;
	}
	//判断下一个结点是不是食物
	if (IF_FOOF(pnew, pp))
	{
		//是食物：
		EatFood(pnew, pp);
		pnew = NULL;
	}
	else
	{
		//不是食物：
		NoFood(pnew, pp);
	}
	//撞到墙
	KillByWall(pp);
	//撞到自己
	KillBySelf(pp);
}


//开始游戏
void StartGame(Snake* ppsnake)
{
	Print_help();
	do {
		Set_Con(64, 12);
		printf("总分数：%d", ppsnake->score);
		Set_Con(64, 13);
		printf("当前每个食物的分数：%02d", ppsnake->foof_weight);
		if (KEY_PASS(VK_UP) && ppsnake->dir != DOWN)//向上
		{
			ppsnake->dir = UP;
		}
		else if (KEY_PASS(VK_DOWN) && ppsnake->dir != UP)//向下
		{
			ppsnake->dir = DOWN;
		}
		else if (KEY_PASS(VK_LEFT) && ppsnake->dir != RIGHT)//向左
		{
			ppsnake->dir = LEFT;
		}
		else if (KEY_PASS(VK_RIGHT) && ppsnake->dir != LEFT)//向右
		{
			ppsnake->dir = RIGHT;
		}
		else if (KEY_PASS(VK_SPACE))//暂停
		{
			PAUSE();
		}
		else if (KEY_PASS(VK_ESCAPE))//正常退出游戏
		{
			ppsnake->status = OVER_NORMAL;
		}
		else if (KEY_PASS(VK_F3))//加速
		{
			if (ppsnake->foof_weight < 18)
			{
				ppsnake->sleep_time -= 30;
				ppsnake->foof_weight += 2;
			}
		}
		else if (KEY_PASS(VK_F4))//减速
		{
			if (ppsnake->foof_weight > 2)
			{
				ppsnake->sleep_time += 30;
				ppsnake->foof_weight -= 2;
			}
		}
		Snakemove(ppsnake);
		Sleep(ppsnake->sleep_time);
	} while (ppsnake->status == REGULAR);
}

//结束游戏
void EndGame(Snake* pp)
{
	switch (pp->status)
	{
	case OVER_BY_SELF:  
		printf("撞到自己了，本局游戏结束！！！");
		break;
	case OVER_BY_WALL:
		printf("撞到墙了，本局游戏结束！！！");
		break;
	case OVER_NORMAL:
		printf("本局游戏已正常退出！！！");
		break;
	}
	//释放结点
	snakeNode* cur = pp->psnake;
	while (cur)
	{
		snakeNode* del = cur;
		cur = cur->next;
		free(del);
	}
}
